/*
#################################################################
#                       LINDO-API
#                    Sample Programs
#                  Copyright (c) 2001-2002
#
#         LINDO Systems, Inc.           312.988.7422
#         1415 North Dayton St.         info@lindo.com
#         Chicago, IL 60622             http://www.lindo.com
#################################################################
  File   : markow.c
  Purpose: Solve a quadratic programming problem.
  Model  : The Markowitz Portfolio Selection Model

           MAXIMIZE  r(1)w(1) + ... +r(n)w(n)
           st.       sum_{ij} Q(i,j)w(i)w(j) <= K
                         w(1) + ..... + w(n)  = 1
                         w(1),         ,w(n) >= 0
           where
           r(i)  : return on asset i
           Q(i,j): covariance between the returns of i^th and
                   j^th assets.
           K     : a scalar denoting the level of risk of loss.
           w(i)  : proportion of total budget invested on asset i

  Covariance Matrix:
          w1    w2    w3    w4
     w1 [ 1.00  0.64  0.27  0.    ]
     w2 [ 0.64  1.00  0.13  0.    ]
     w3 [ 0.27  0.13  1.00  0.    ]
     w4 [ 0.    0.    0.    1.00  ]

  Returns Vector:
          w1    w2    w3    w4
  r =   [ 0.30  0.20 -0.40  0.20  ]

  Risk of Loss Factor:
  K = 0.4

*/
#include 
#include 
#include 
#include "lindo.h"
#include "license.h"
/* Define a macro to declare variables for
    error checking */
#define APIERRORSETUP  \
   int nErrorCode; \
   char cErrorMessage[LS_MAX_ERROR_MESSAGE_LENGTH] \
/* Define a macro to do our error checking */
#define APIERRORCHECK  \
   if (nErrorCode) \
   { \
      if ( pEnv) \
      { \
         LSgetErrorMessage( pEnv, nErrorCode, \
          cErrorMessage); \
         printf("Errorcode=%d:  %s\n", nErrorCode, \
          cErrorMessage); \
      } else {\
         printf( "Fatal Error\n"); \
      } \
      exit(1); \
   } \
/* main entry point */
int main(int argc, char **argv)
{
   APIERRORSETUP;   
   int nM = 2;      /* Number of constraints */
   int nN = 4;      /* Number of assets */
   
   double K = 0.20; /* 1/2 of the risk level*/

  /* declare an instance of the LINDO environment object */
   pLSenv pEnv;
  /* declare an instance of the LINDO model object */
   pLSmodel pModel;
  /****************************************************************
   * Step 1: Create a LINDO environment. MY_LICENSE_KEY in licence.h
   * must be defined using the key shipped with your software.
   ****************************************************************/
   pEnv = LScreateEnv ( &nErrorCode, MY_LICENSE_KEY);
   if ( nErrorCode == LSERR_NO_VALID_LICENSE)
   {
      printf( "Invalid License Key!\n");
      exit( 1);
   }
   APIERRORCHECK;
  /****************************************************************
   * Step 2: Create a model in the environment.
   ****************************************************************/
   pModel = LScreateModel ( pEnv, &nErrorCode);
   APIERRORCHECK;
  /*****************************************************************
   * Step 3: Specify and load the LP portion of the model.
   *****************************************************************/
   {
     /* The direction of optimization */
      int objsense = LS_MAX;
      /* The objective's constant term */
      double objconst = 0.;
      /* The coefficients of the objective function are the expected
      returns*/
      double reward[4] = { .3, .2, -.4, .2};
      /* The right-hand sides of the constraints */
      double rhs[2] = { K, 1.0 };
      /* The constraint types */
      char contype[2] = {'L','E'};
      /* The number of nonzeros in the constraint matrix */
      int Anz = 4;
      /* The indices of the first nonzero in each column */
      int Abegcol[5] = { 0, 1, 2, 3, Anz};
      /* The length of each column.  Since we aren't leaving
       * any blanks in our matrix, we can set this to NULL */
      int *Alencol = NULL;
      /* The nonzero coefficients */
      double A[4] = { 1., 1., 1., 1.};
      /* The row indices of the nonzero coefficients */
      int Arowndx[4] = { 1, 1, 1, 1};
      /* By default, all variables have a lower bound of zero
       * and an upper bound of infinity.  Therefore pass NULL
       * pointers in order to use these default values. */
      double *lb = NULL, *ub = NULL;
  /*****************************************************************
   * Step 4: Specify and load the quadratic matrix
   *****************************************************************/
     /* The number of nonzeros in the quadratic matrix */
      int Qnz = 7;
      /* The nonzero coefficients in the Q-matrix */
      double Q[7] = { 1.00, .64, .27,
                           1.00, .13,
                                1.00,
                                      1.00} ;
      /* Specify the row indices of the nonzero coefficients in the
         Q-matrix. */
      int Qrowndx[7] = { 0, 0, 0, 0, 0, 0, 0};
      /* The indices of variables in the Q-matrix */
      int Qcolndx1[7] = {  0, 1, 2, 1, 2, 2, 3};
      int Qcolndx2[7] = {  0, 0, 0, 1, 1, 2, 3};
      /* Pass the linear portion of the data to problem structure
       * by a call to LSloadLPData() */
      nErrorCode = LSloadLPData( pModel, nM, nN, objsense, objconst,
                                reward, rhs, contype,
                                Anz, Abegcol, Alencol, A, Arowndx,
                                lb, ub);
      APIERRORCHECK;
     /* Pass the quadratic portion of the data to problem structure
      * by a call to LSloadQCData()  */
      nErrorCode = LSloadQCData(pModel, Qnz, Qrowndx,
                                 Qcolndx1, Qcolndx2, Q );
      APIERRORCHECK;
   }
  /*****************************************************************
   * Step 5: Perform the optimization using the barrier solver
   *****************************************************************/
   nErrorCode = LSoptimize( pModel, LS_METHOD_BARRIER,NULL);
   APIERRORCHECK;
  /***************************************************************
   * Step 6: Retrieve the solution
   ***************************************************************/
   {
      int i;
      double W[4], dObj;
   /* Get the value of the objective */
      nErrorCode = LSgetInfo( pModel, LS_DINFO_POBJ, &dObj) ;
      APIERRORCHECK;
      printf( "* Objective Value = %10g\n\n", dObj);
    /* Get the portfolio */
      nErrorCode = LSgetPrimalSolution ( pModel, W);
      APIERRORCHECK;
      printf ("* Optimal Portfolio : \n");
      for (i = 0; i < nN; i++)
      printf( "Invest %5.2f percent of total budget in asset %d.\n",
               100*W[i],i+1 );
      printf ("\n");
   }
  /***************************************************************
   * Step 7: Delete the LINDO environment
   *****************************************************************/
   nErrorCode = LSdeleteEnv( &pEnv);
   /* Wait until user presses the Enter key */
   printf("Press  ...");
   getchar();
}